package com.nuoniu.sibanyun.service.production.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.entity.bo.VoucherDetailBo;
import com.nuoniu.sibanyun.entity.bo.VoucherMainBo;
import com.nuoniu.sibanyun.entity.bo.VoucherSearchBo;
import com.nuoniu.sibanyun.entity.dto.VProductionOrderDetailSaveDto;
import com.nuoniu.sibanyun.entity.dto.VProductionOrderMainSaveDto;
import com.nuoniu.sibanyun.entity.erp.ErpNumberSet;
import com.nuoniu.sibanyun.entity.inOut.VInOutRecordDetail;
import com.nuoniu.sibanyun.entity.inOut.VInOutRecordMain;
import com.nuoniu.sibanyun.entity.po.VPoPurchaseOrderDetail;
import com.nuoniu.sibanyun.entity.po.VPoPurchaseOrderMain;
import com.nuoniu.sibanyun.entity.production.*;
import com.nuoniu.sibanyun.mapper.erp.ErpNumberSetMapper;
import com.nuoniu.sibanyun.mapper.production.VProductionOrderMainMapper;
import com.nuoniu.sibanyun.service.crm.ICrmGoodsService;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpNumberSetService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherDesignService;
import com.nuoniu.sibanyun.service.production.IVProductionOrderDetailService;
import com.nuoniu.sibanyun.service.production.IVProductionOrderMainService;
import com.nuoniu.sibanyun.service.utils.ErpUtils;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 生产订单主表 服务实现类
 * </p>
 *
 * @author 小啊刚
 * @since 2021-03-08
 */
@Log4j2
@Service
public class VProductionOrderMainServiceImpl extends ServiceImpl<VProductionOrderMainMapper, VProductionOrderMain> implements IVProductionOrderMainService {

    @Autowired
    private IVProductionOrderDetailService productionOrderDetailService;
    @Autowired
    private IErpAccountService accountService;
    @Autowired
    private ErpNumberSetMapper numberSetMapper;
    @Autowired
    private IErpNumberSetService numberSetService;
    @Autowired
    private IErpVoucherDesignService erpVoucherDesignService;
    @Autowired
    private ICrmGoodsService crmGoodsService;

    @Override
    public void saveOrder(VProductionOrderMain productionOrderMain) {
        Boolean isNewMain = false;
        List<VProductionOrderDetail> orderDetailList = productionOrderMain.getOrderDetailList();
        if(null == orderDetailList)throw new NuoNiuException("单据明细不能为空");
        Long mainId = productionOrderMain.getId();
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = accountService.getCurrentAccountId();
        VProductionOrderMain oldVProductionOrderMain = null;
        if(productionOrderMain.getId() == null) {
            isNewMain = true;
            productionOrderMain.setBusinessType(0);
            productionOrderMain.setVoucherState(-1);
            productionOrderMain.setCompanyId(userInfo.getCompanyId());
            productionOrderMain.setAccountId(currentAccountId);
            productionOrderMain.setCreateUserId(userInfo.getUserId());
            productionOrderMain.setVoucherCode(getCode());
            productionOrderMain.setCreateUserName(userInfo.getRealName());
        }else{
            //校验详情（详情不能有其他单据的明细ID）
            boolean isHaveErrorId = orderDetailList.stream().anyMatch(f -> null != f.getOrderId() && !mainId.toString().equals(f.getOrderId().toString()));
            if(isHaveErrorId)throw new NuoNiuException("单据明细错误：不能修改其他单据的明细记录");
            oldVProductionOrderMain = getById(mainId);
            /**************  修改权限 *******************/
            if(!crmGoodsService.isHaveOperationRight(oldVProductionOrderMain.getCreateUserId().longValue())){
                throw new NuoNiuException("你没有权限操作该记录");
            }
            Integer voucherState = oldVProductionOrderMain.getVoucherState();
            if(null != voucherState && voucherState > 0){
                throw new NuoNiuException("已审核,不能修改");
            }
            productionOrderMain.setAccountId(oldVProductionOrderMain.getAccountId());
            productionOrderMain.setSourceVoucherCode(oldVProductionOrderMain.getSourceVoucherCode());
            productionOrderMain.setSourceVoucherId(oldVProductionOrderMain.getSourceVoucherId());
            productionOrderMain.setSourceVoucherType(oldVProductionOrderMain.getSourceVoucherType());
            productionOrderMain.setSourceVoucherDate(oldVProductionOrderMain.getSourceVoucherDate());
            //不可更新字段
            productionOrderMain.setVoucherCode(null);
        }
        // 校验 明细数量
        boolean isOk = orderDetailList.stream().anyMatch(f -> null == f.getBaseQuantity() || !(f.getBaseQuantity().compareTo(BigDecimal.ZERO) > 0));
        if(isOk)throw new NuoNiuException("明细数量必须大于0");
        //计算 明细物料 总数
        BigDecimal totalQuantity =  orderDetailList.stream().map(VProductionOrderDetail::getBaseQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
        productionOrderMain.setTotalQuantity(totalQuantity.abs());
        Boolean result = this.saveOrUpdate(productionOrderMain);
        if(result) {
            List<Long> detailIds = new ArrayList<>();
            orderDetailList.forEach(p -> {
                p.setAccountId(accountService.getCurrentAccountId());
                p.setCompanyId(userInfo.getCompanyId());
                p.setOrderId(productionOrderMain.getId().intValue());
                //添加 不删除的明细ID
                if (p.getId() != null) {
                    detailIds.add(p.getId());
                }
            });

            boolean isDealDelete = false;
            if (null != mainId){
                //删除明细
                QueryWrapper wrapper = new QueryWrapper();
                wrapper.eq("order_id", mainId);
                if(detailIds != null && detailIds.size() > 0) {
                    wrapper.notIn("id", detailIds);
                }
                isDealDelete = productionOrderDetailService.remove(wrapper);
            }
            //保存单据明细表
            productionOrderDetailService.saveOrUpdateBatch(orderDetailList);
            // *** 如果 来源订单不为空,校验
            if(null != productionOrderMain.getSourceVoucherId()){
//                if(!"ProductionPlan".equals(productionOrderMain.getSourceVoucherType()))throw new NuoNiuException("生产订单的来源单，只能是生产计划");
                VoucherMainBo voucherMainBo = new VoucherMainBo();
                BeanUtils.copyProperties(productionOrderMain,voucherMainBo);
                voucherMainBo.setIsNewMain(isNewMain);
                List<VoucherDetailBo> voucherDetailBos = new ArrayList<>();
                orderDetailList.forEach(detail->{
                    VoucherDetailBo voucherDetailBo = new VoucherDetailBo();
                    voucherDetailBos.add(voucherDetailBo);
                    BeanUtils.copyProperties(detail,voucherDetailBo);
                });
                VoucherSearchBo voucherSearchBo = new VoucherSearchBo();
                voucherSearchBo.setSourceVoucherId(productionOrderMain.getSourceVoucherId());
                voucherSearchBo.setSourceVoucherType(productionOrderMain.getSourceVoucherType());
                voucherSearchBo.setVoucherId(productionOrderMain.getId().intValue());
                voucherSearchBo.setVoucherType("ProductionOrder");
                erpVoucherDesignService.calculateSourceVoucher(voucherMainBo,voucherDetailBos,voucherSearchBo);
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Set<Long> saveOrderForCustomer(VProductionOrderMainSaveDto productionOrderMainSaveDto) {
        Set<Long> idSet = new HashSet<>();
        Map<Integer,List<VProductionOrderDetailSaveDto>> idMap = new HashMap<>();
        List<VProductionOrderDetailSaveDto> orderDetailSaveDtoListList = productionOrderMainSaveDto.getOrderDetailList();
        orderDetailSaveDtoListList.forEach(detail->{
            Integer crmId = detail.getCrmId();
            List<VProductionOrderDetailSaveDto> productionOrderDetailSaveDtoList = idMap.get(crmId);
            if (null == productionOrderDetailSaveDtoList) {
                productionOrderDetailSaveDtoList = new ArrayList<>();
                idMap.put(crmId,productionOrderDetailSaveDtoList);
            }
            productionOrderDetailSaveDtoList.add(detail);
        });
        for(Integer crmId:idMap.keySet()){
            VProductionOrderMain newMain = new VProductionOrderMain();
            BeanUtils.copyProperties(productionOrderMainSaveDto,newMain);
            List<VProductionOrderDetailSaveDto> vProductionOrderDetailSaveDtoList = idMap.get(crmId);
            BigDecimal totalQuantity = vProductionOrderDetailSaveDtoList.stream().map(VProductionOrderDetailSaveDto::getBaseQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
            newMain.setTotalQuantity(totalQuantity.abs());
            VProductionOrderDetailSaveDto vProductionOrderDetailSaveDto = vProductionOrderDetailSaveDtoList.get(0);
            String crmName = vProductionOrderDetailSaveDto.getCrmName();
            newMain.setCrmId(crmId);
            newMain.setCrmName(crmName);
            List<VProductionOrderDetail> orderDetailList = new ArrayList<>();
            vProductionOrderDetailSaveDtoList.forEach(detailDto->{
                VProductionOrderDetail newDetail = new VProductionOrderDetail();
                BeanUtils.copyProperties(detailDto,newDetail);
                orderDetailList.add(newDetail);
            });
            newMain.setOrderDetailList(orderDetailList);
            saveOrder(newMain);
            idSet.add(newMain.getId());
        }
        return idSet;
    }

    @Override
    public String getCode() {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = accountService.getCurrentAccountId();
        ErpNumberSet numberSet = numberSetMapper.getByCode("ProductionOrder", userInfo.getCompanyId(), currentAccountId);
        String dateStr = numberSet.getMedian() == 1 ? "%Y-%m-%d" : "%Y-%m";
        String code = baseMapper.getNewestCode(userInfo.getCompanyId(), dateStr);
        return numberSetService.getCode(numberSet, code);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void delete(Long id) {
        UserInfo userInfo = UserThreadLocal.get();
        VProductionOrderMain orderMain = getById(id);
        if(orderMain == null) {
            throw new NuoNiuException("删除失败，记录不存在");
        }
        /**************  修改权限 *******************/
        if(!crmGoodsService.isHaveOperationRight(orderMain.getCreateUserId().longValue())){
            throw new NuoNiuException("你没有权限操作该记录");
        }
        BigDecimal cumExecuteQuantity = orderMain.getCumExecuteQuantity();
        if(null != cumExecuteQuantity && cumExecuteQuantity.compareTo(BigDecimal.ZERO) > 0){
            throw new NuoNiuException("已经生单，不能删除");
        }
        //如果 来源订单 不为空
        if(null != orderMain.getSourceVoucherId()){
            //查询 单据明细
            List<VProductionOrderDetail> orderDetails = productionOrderDetailService.getOrderDetails(id);
            VoucherMainBo voucherMainBo = new VoucherMainBo();
            BeanUtils.copyProperties(orderMain,voucherMainBo);
            List<VoucherDetailBo> voucherDetailBos = new ArrayList<>();
            orderDetails.forEach(detail->{
                VoucherDetailBo voucherDetailBo = new VoucherDetailBo();
                voucherDetailBos.add(voucherDetailBo);
                BeanUtils.copyProperties(detail,voucherDetailBo);
            });
            VoucherSearchBo voucherSearchBo = new VoucherSearchBo();
            voucherSearchBo.setCalculateType(2);
            voucherSearchBo.setSourceVoucherId(orderMain.getSourceVoucherId());
            voucherSearchBo.setSourceVoucherType(orderMain.getSourceVoucherType());
            voucherSearchBo.setVoucherId(orderMain.getId().intValue());
            voucherSearchBo.setVoucherType("ProductionOrder");
            erpVoucherDesignService.calculateSourceVoucher(voucherMainBo,voucherDetailBos,voucherSearchBo);
        }
        removeById(id);
        productionOrderDetailService.removeByOrderId(id);
        log.info("租户：{}，用户：{}，删除生产订单编号：{}，ID:{}",userInfo.getCompanyName(),userInfo.getRealName(),orderMain.getVoucherCode(),orderMain.getId());

    }

    @Override
    public void submit(Long id, Integer status) {
        if(null == id || null == status || (null != status && (status > 0 || status < -1 )))throw new NuoNiuException("参数错误");
        UserInfo userInfo = UserThreadLocal.get();
        VProductionOrderMain main = this.getById(id);
        if( null == main)throw new NuoNiuException("记录不存在");
        //校验状态
        Integer voucherState = main.getVoucherState();
        /**  统一校验 提交状态 */
        ErpUtils.checkSubmitStatus(voucherState,status);
        //提交
        main.setVoucherState(status);
        main.setSubmitDate(LocalDateTime.now());
        main.setSubmitUserId(userInfo.getUserId());
        main.setSubmitUserName(userInfo.getRealName());
        this.updateById(main);
    }

    @Override
    public void examine(Long id, Integer status) {
        UserInfo userInfo = UserThreadLocal.get();
        VProductionOrderMain oldVProductionOrderMain = getById(id);
        BigDecimal cumExecuteQuantity = oldVProductionOrderMain.getCumExecuteQuantity();
        if(null != cumExecuteQuantity && cumExecuteQuantity.compareTo(BigDecimal.ZERO) > 0) throw new NuoNiuException("已经生单，不能做弃审操作");

        VProductionOrderMain productionPickReturnMain = new VProductionOrderMain();
        productionPickReturnMain.setVoucherState(status);
        productionPickReturnMain.setId(id);
        productionPickReturnMain.setReviewerUserName(userInfo.getRealName());
        productionPickReturnMain.setReviewerUserId(userInfo.getUserId());
        updateById(productionPickReturnMain);
    }
}
